﻿using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace Kindohm.KSynth.Library
{
    public class Sequencer : AttenuatorBase, ISampleMaker
    {
        int tempo;
        int sampleCounter;
        int samplesPerQuarter;
        int stepCount;
        int stepIndex;
        Dictionary<int, Step> steps;
        int elapsedSeconds = 0;
        int elapsedSampleTicks = 0;

        public Sequencer()
        {
            this.steps = new Dictionary<int, Step>();
            this.Tempo = 2000;
            this.StepCount = 32;
        }

        public Synthesizer Synthesizer { get; set; }

        public int StepCount
        {
            get { return this.stepCount; }
            set
            {
                this.stepCount = value;
                this.OnStepCountChanged();
            }
        }

        public int Tempo
        {
            set
            {
                this.tempo = value;
                this.samplesPerQuarter = 44100 * 60 / this.tempo;
            }
            get
            {
                return tempo;
            }
        }

        public StereoSample GetSample()
        {

            sampleCounter++;

            if (sampleCounter > samplesPerQuarter)
            {
                this.stepIndex++;

                Step step = this.steps[this.stepIndex];

                if (step.Pitch != null)
                {
                    this.Synthesizer.Frequency = step.Pitch.Frequency;
                    this.Synthesizer.Envelope.Reset();
                }

                sampleCounter = 0;

                if (this.StepPlayed != null)
                {
                    TimeSpan elapsed = TimeSpan.FromSeconds(elapsedSeconds + elapsedSampleTicks / 44100.0);
                    this.StepPlayed(this, new StepPlayedEventArgs() { Step = this.stepIndex, ElapsedTime = elapsed });
                }

                if (this.stepIndex >= this.StepCount)
                    this.stepIndex = 0;
            }

            if (++elapsedSampleTicks == 44100)
            {
                elapsedSeconds++;
                elapsedSampleTicks = 0;
            } 



            StereoSample sample = this.Synthesizer.GetSample();

            return this.Attenuate(sample);
        }

        public void SetStepPitch(int stepNumber, Pitch value)
        {
            this.steps[stepNumber].Pitch = value;
        }

        void OnStepCountChanged()
        {
            if (this.StepCount > this.steps.Count)
            {
                for (int i = this.steps.Count; i < this.StepCount; i++)
                {
                    this.steps.Add(i + 1, new Step());
                }
            }

            for (int i = 1; i <= this.steps.Count; i++)
            {
                if (i <= this.StepCount)
                {
                    this.steps[i].Enabled = true;
                }
                else
                {
                    this.steps[i].Enabled = false;
                }
            }
        }

        public event EventHandler<StepPlayedEventArgs> StepPlayed;
    }
}
